package com.ibm.cloud.banking.sample.aop;

import com.ibm.cloud.banking.annotation.PBS;
import com.ibm.cloud.banking.platform.context.model.RequestContextEnum;
import com.ibm.cloud.banking.platform.context.service.RequestContextHandler;
import com.ibm.cloud.banking.sample.dto.OePbsLogDTO;
import com.ibm.cloud.banking.sample.entity.OePbsLogEntityPK;
import com.ibm.cloud.banking.sample.service.IPbsLogService;

import org.springframework.aop.Advisor;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;

import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;

/**
 * replace desc in here
 *
 * @author HanDong
 * @date 2022/7/26
 */

@Component
@Slf4j
public class PbsLogAspect {

    private static final String FORWARD_METHOD = "doService";
    private static final String REVERSE_METHOD = "compensate";
    /**
     * PBS 正向0 反向1
     */
    private static final String PBS_SERVICE_FORWARD_TYPE = "0";
    private static final String PBS_SERVICE_REVERSE_TYPE = "1";
    @Resource
    private IPbsLogService pbsLogService;

    @Bean
    public Advisor pbsLogAdvisor() {
        return new DefaultPointcutAdvisor(new AnnotationMatchingPointcut(PBS.class, true), new MethodAroundAdvice());
    }

    private class MethodAroundAdvice implements MethodBeforeAdvice, AfterReturningAdvice {

        @Override
        public void before(Method method, Object[] args, Object target) {

            if (FORWARD_METHOD.equals(method.getName())) {
                log.info("全局流水号{}", RequestContextHandler.getContext().getReqGlbSerNo());
                RequestContextHandler.putCompensate(RequestContextEnum.reqGlbSerNo.name(),
                        RequestContextHandler.getContext().getReqGlbSerNo());

                pbsLogService.saveLog(OePbsLogDTO
                        .builder()
                        .id(RequestContextHandler.getContext().getReqGlbSerNo())
                        .pbsId(target.getClass().getSimpleName())
                        .servType(PBS_SERVICE_FORWARD_TYPE)
                        .pbsParameter(Arrays.deepToString(args))
                        .build());


            } else {
                /**
                 * 预插入占位流水
                 */
                try {
                    pbsLogService.saveLog(OePbsLogDTO
                            .builder()
                            .id(RequestContextHandler.getCompensate(RequestContextEnum.reqGlbSerNo.name())
                                    .toString())
                            .pbsId(target.getClass().getSimpleName())
                            .servType(PBS_SERVICE_FORWARD_TYPE)
                            .pbsParameter("compensate-auto")
                            .build());
                } catch (Exception e) {
                    log.info("反向补偿插入正向占位流水失败，忽略说明正交易完成流水记录完整");
                }
                /**
                 * 反向正常流水
                 */
                try {
                    pbsLogService.saveLog(OePbsLogDTO
                            .builder()
                            .id(RequestContextHandler.getCompensate(RequestContextEnum.reqGlbSerNo.name())
                                    .toString())
                            .pbsId(target.getClass().getSimpleName())
                            .servType(PBS_SERVICE_REVERSE_TYPE)
                            .pbsParameter(Arrays.deepToString(args))
                            .build());
                }catch(Exception e) {
                    log.info("反向补偿插入正向占位流水失败，已补偿过");
                }
            }
        }

        @Override
        public void afterReturning(Object returnValue, Method method, Object[] args, Object target) {
            if (FORWARD_METHOD.equals(method.getName())) {

                pbsLogService.updateLog(
                        OePbsLogEntityPK.builder().id(RequestContextHandler.getContext().getReqGlbSerNo())
                                .pbsId(target.getClass().getSimpleName())
                                .servType(PBS_SERVICE_FORWARD_TYPE)
                                .build(), null == returnValue ? null : returnValue.toString());

            } else {

                pbsLogService.updateLog(
                        OePbsLogEntityPK.builder().id(RequestContextHandler.getCompensate(RequestContextEnum.reqGlbSerNo.name())
                                        .toString())
                                .pbsId(target.getClass().getSimpleName())
                                .servType(PBS_SERVICE_REVERSE_TYPE)
                                .build(), null == returnValue ? null : returnValue.toString());

            }
        }
    }


}
